#pragma once
#include <string>

/*******************************************************
 *
 * exstring
 *
 *******************************************************/

class exstring : public std::string
{
public:
	exstring(
	   const char* _Ptr, 
	   size_t _Count) : std::string(_Ptr, _Count)
	{
	}

	exstring(
	   const char* _Ptr) : std::string(_Ptr)
	{
	}

	exstring(
		const wchar_t* _Ptr)
	{
		operator=(_Ptr);
	}

	exstring(
	   const std::string& _Right, 
	   size_t _Roff = 0, 
	   size_t _Count = npos) : std::string(_Right, _Roff, _Count)
	{
	}

	exstring(
	   size_t _Count,
	   char _Ch) : std::string(_Count, _Ch)
	{
	}

	exstring()
	{
	}

	exstring& operator=(const wchar_t* _Ptr)
	{
		clear();
		if(_Ptr)
		{
			int nLength = 0;
			char* pBuffer = NULL;

			nLength = ::WideCharToMultiByte(CP_ACP, 0, _Ptr, -1, NULL, 0, NULL, NULL);
			if(nLength > 0)
			{
				pBuffer = new char[nLength + 1];
				::WideCharToMultiByte(CP_ACP, 0, _Ptr, -1, pBuffer, nLength + 1, NULL, NULL);
				pBuffer[nLength] = 0;
				*this = pBuffer;
				delete[] pBuffer;
			}
		}

		return *this;
	}

	exstring& operator+=(const char* _Ptr)
	{
		std::string::operator+=(_Ptr);
		return *this;
	}

	operator const char*() const
	{
		return this->c_str();
	}

	bool operator==(const std::string& _Right)
	{
		return (strcmp(this->c_str(), _Right.c_str()) == 0);
	}

	bool operator!=(const std::string& _Right)
	{
		return !(operator==(_Right));
	}

	bool operator==(const char* _Right)
	{
		return (strcmp(this->c_str(), _Right) == 0);
	}

	bool operator!=(const char* _Right)
	{
		return !(operator==(_Right));
	}

	bool operator>(const std::string& _Right)
	{
		return (strcmp(this->c_str(), _Right.c_str()) > 0);
	}

	bool operator>(const char* _Right)
	{
		return (strcmp(this->c_str(), _Right) > 0);
	}

	bool operator>=(const std::string& _Right)
	{
		return (strcmp(this->c_str(), _Right.c_str()) >= 0);
	}

	bool operator>=(const char* _Right)
	{
		return (strcmp(this->c_str(), _Right) >= 0);
	}

	bool operator<(const std::string& _Right)
	{
		return (strcmp(this->c_str(), _Right.c_str()) < 0);
	}

	bool operator<(const char* _Right)
	{
		return (strcmp(this->c_str(), _Right) < 0);
	}

	bool operator<=(const std::string& _Right)
	{
		return (strcmp(this->c_str(), _Right.c_str()) <= 0);
	}

	bool operator<=(const char* _Right)
	{
		return (strcmp(this->c_str(), _Right) <= 0);
	}

	exstring left(size_t _Length)
	{
		return substr(0, _Length);
	}

	exstring right(size_t _Length)
	{
		return substr(length() - _Length, _Length);
	}

	exstring& format(const char* fmt, ...)
	{
		char* szBuffer = NULL;
		int nBufLen = 0;
		va_list ap;
	    
		va_start(ap, fmt);

		nBufLen = _vscprintf(fmt, ap) + 1;
		szBuffer = new char[nBufLen];
		vsprintf_s(szBuffer, nBufLen, fmt, ap);
		*this = szBuffer;
		delete[] szBuffer;

		va_end(ap);

		return *this;
	}

	exstring& append_format(const char* fmt, ...)
	{
		char* szBuffer = NULL;
		int nBufLen = 0;
		va_list ap;
	    
		va_start(ap, fmt);

		nBufLen = _vscprintf(fmt, ap) + 1;
		szBuffer = new char[nBufLen];
		vsprintf_s(szBuffer, nBufLen, fmt, ap);
		*this += szBuffer;
		delete[] szBuffer;

		va_end(ap);

		return *this;
	}

	exstring& tolower()
	{
		size_t szLength = length();
		for(size_t i = 0; i < szLength; i++)
		{
			operator[](i) = (char)::tolower(operator[](i));
		}

		return *this;
	}

	exstring& toupper()
	{
		size_t szLength = length();
		for(size_t i = 0; i < szLength; i++)
		{
			operator[](i) = (char)::toupper(operator[](i));
		}

		return *this;
	}

	exstring& replace(const char* dst, const char* rpl)
	{
		int dst_len = strlen(dst);
		while(true)
		{
			size_t pos = this->find(dst);
			if(pos != npos)
			{
				std::string::replace(pos, dst_len, rpl);
			}
			else
			{
				break;
			}
		}

		return *this;
	}
};

/*******************************************************
 *
 * wexstring
 *
 *******************************************************/

class wexstring : public std::wstring
{
public:
	wexstring(
	   const wchar_t* _Ptr, 
	   size_t _Count) : std::wstring(_Ptr, _Count)
	{
	}

	wexstring(
	   const wchar_t* _Ptr) : std::wstring(_Ptr)
	{
	}

	wexstring(
		const char* _Ptr)
	{
		operator=(_Ptr);
	}

	wexstring(
	   const std::wstring& _Right, 
	   size_t _Roff = 0, 
	   size_t _Count = npos) : std::wstring(_Right, _Roff, _Count)
	{
	}

	wexstring(
	   size_t _Count,
	   wchar_t _Ch) : std::wstring(_Count, _Ch)
	{
	}

	wexstring()
	{
	}

	wexstring& operator=(const char* _Ptr)
	{
		clear();
		if(_Ptr)
		{
			int nLength = 0;
			wchar_t* pBuffer = NULL;

			nLength = ::MultiByteToWideChar(CP_ACP, 0, _Ptr, -1, NULL, 0);
			if(nLength > 0)
			{
				pBuffer = new wchar_t[nLength + 1];
				::MultiByteToWideChar(CP_ACP, 0, _Ptr, -1, pBuffer, nLength + 1);
				pBuffer[nLength] = 0;
				*this = pBuffer;
				delete[] pBuffer;
			}
		}

		return *this;
	}

	wexstring& operator+=(const wchar_t* _Ptr)
	{
		std::wstring::operator+=(_Ptr);
		return *this;
	}

	operator const wchar_t*() const
	{
		return this->c_str();
	}

	bool operator==(const std::wstring& _Right)
	{
		return (wcscmp(this->c_str(), _Right.c_str()) == 0);
	}

	bool operator!=(const std::wstring& _Right)
	{
		return !(operator==(_Right));
	}

	bool operator==(const wchar_t* _Right)
	{
		return (wcscmp(this->c_str(), _Right) == 0);
	}

	bool operator!=(const wchar_t* _Right)
	{
		return !(operator==(_Right));
	}

	bool operator>(const std::wstring& _Right)
	{
		return (wcscmp(this->c_str(), _Right.c_str()) > 0);
	}

	bool operator>(const wchar_t* _Right)
	{
		return (wcscmp(this->c_str(), _Right) > 0);
	}

	bool operator>=(const std::wstring& _Right)
	{
		return (wcscmp(this->c_str(), _Right.c_str()) >= 0);
	}

	bool operator>=(const wchar_t* _Right)
	{
		return (wcscmp(this->c_str(), _Right) >= 0);
	}

	bool operator<(const std::wstring& _Right)
	{
		return (wcscmp(this->c_str(), _Right.c_str()) < 0);
	}

	bool operator<(const wchar_t* _Right)
	{
		return (wcscmp(this->c_str(), _Right) < 0);
	}

	bool operator<=(const std::wstring& _Right)
	{
		return (wcscmp(this->c_str(), _Right.c_str()) <= 0);
	}

	bool operator<=(const wchar_t* _Right)
	{
		return (wcscmp(this->c_str(), _Right) <= 0);
	}

	wexstring left(size_t _Length)
	{
		return substr(0, _Length);
	}

	wexstring right(size_t _Length)
	{
		return substr(length() - _Length, _Length);
	}

	wexstring& format(const wchar_t* fmt, ...)
	{
		wchar_t* szBuffer = NULL;
		int nBufLen = 0;
		va_list ap;
	    
		va_start(ap, fmt);

		nBufLen = _vscwprintf(fmt, ap) + 1;
		szBuffer = new wchar_t[nBufLen];
		vswprintf_s(szBuffer, nBufLen, fmt, ap);
		*this = szBuffer;
		delete[] szBuffer;

		va_end(ap);

		return *this;
	}

	wexstring& append_format(const wchar_t* fmt, ...)
	{
		wchar_t* szBuffer = NULL;
		int nBufLen = 0;
		va_list ap;
	    
		va_start(ap, fmt);

		nBufLen = _vscwprintf(fmt, ap) + 1;
		szBuffer = new wchar_t[nBufLen];
		vswprintf_s(szBuffer, nBufLen, fmt, ap);
		*this += szBuffer;
		delete[] szBuffer;

		va_end(ap);

		return *this;
	}

	wexstring& tolower()
	{
		size_t szLength = length();
		for(size_t i = 0; i < szLength; i++)
		{
			operator[](i) = (wchar_t)::towlower(operator[](i));
		}

		return *this;
	}

	wexstring& toupper()
	{
		size_t szLength = length();
		for(size_t i = 0; i < szLength; i++)
		{
			operator[](i) = (wchar_t)::towupper(operator[](i));
		}

		return *this;
	}

	wexstring& replace(const wchar_t* dst, const wchar_t* rpl)
	{
		int dst_len = wcslen(dst);
		while(true)
		{
			size_t pos = this->find(dst);
			if(pos != npos)
			{
				std::wstring::replace(pos, dst_len, rpl);
			}
			else
			{
				break;
			}
		}

		return *this;
	}
};
